目標:重構導航頁尾元件以使用 SocialMediaComponenet 和 Icon 元件。
The inline template of the NavFooterComponent was long and I refactored the HTML codes into icon components and a social media component.
NavFooterComponent 的內嵌範本很長,我將 HTML 程式碼重構為 SocialMediaComponent 和 Icon 元件。
GithubIconComponent、TwitterXIconComponent 和 LinkedinComponent。SocialMediaComponent 以透過 NgComponentOutlet 投影 Icon 元件。import { Component } from '@angular/core';
@Component({
 selector: 'blog-github-icon',
 standalone: true,
 template:`
   <svg …><path … /></svg>
 `,
})
export class GithubIconComponent {}
@Component({
 selector: 'blog-linkedin-icon',
 standalone: true,
 template:`
   <svg …><path … /></svg>
 `,
})
export class LinkedinIconComponent {}
@Component({
 selector: 'blog-twitter-x-icon',
 standalone: true,
 template:`
   <svg …><path … /></svg>
 `,
})
export class TwitterXIconComponent {}
將 svg 重構為 GithubIconComponent、 LinkedinIconComponent 和 TwitterXIconComponent。
SocialMedialComponent 使用 <ng-content> 來投影 Icon 元件。
export type SocialMedia = {
   href: string;
   text: string;
}
import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';
import { SocialMedia } from '../types/social-media.type';
@Component({
 selector: 'blog-social-media',
 standalone: true,
 template: `
   @let info = information();
   <a [href]="info.href" target="_blank" [ariaDescription]="info.text">
     <span class="mr-2">{{ info.text }}</span> 
     <ng-content />
   </a>`,
 changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SocialMediaComponent { 
 information = input.required<SocialMedia>();
}
SocialMediaComponent 元件的 signal input 包含顯示我的社群個人資料的文字和 URL。
export class NavFooterComponent {
 socialMedia = signal<{ [key: string]: SocialMedia }>({
   github: {
     href: 'https://github.com/railsstudent',
     text: 'Github',
   },
   twitter: {
     href: 'https://x.com/connieleung404',
     text: 'Twitter',
   },
   linkedin: {
     href: 'https://www.linkedin.com/in/connieleung107/',
     text: 'Linkedin',
   }
 });
}
socialMedia signal 分別儲存我的 Github、Twitter 和 Linkedin 的 URL 和文字。
keys = computed(() => Object.keys(this.socialMedia()));
components = computed(() => ({
     github: GithubIconComponent,
     twitter: TwitterXIconComponent,
     linkedin: LinkedinIconComponent
} as { [key: string] : any }));
keys computed signal 將 socialMedia 的鍵儲存在 array 中。 computed signal 將鍵映射到icon 元件。
imports: [SocialMediaComponent, GithubIconComponent, LinkedinIconComponent, TwitterXIconComponent, NgComponentOutlet],
template: `
       ...
       <div class="flex flex-row basis-1/4">
         @for (key of keys(); track key) {
           <blog-social-media [information]="socialMedia()[key]" class="grow shrink basic-1/3">
             <ng-container *ngComponentOutlet="components()[key]" />
           </blog-social-media>
         }
       </div>
     ...
 `,
將 GithubIconComponent、LinkedinIconComponent、TwitterXIconComponent 和 NgComponentOutlet 匯入 imports array 中。
編寫一個 @for,將我的社群媒體帳號的 URL 和文字傳遞給 SocialMediaComponent 元件進行顯示。此外,ngComponentOutlet directive 被指派了一個 icon 元件來渲染 SVG 圖示。
在瀏覽器上導航至 http://localhost:5173/,頁面應保持不變。
您可能認為重構會產生更多文件和程式碼,但 NavFooterComponent 的範本乾淨且簡短。與長 svg 代碼相比,我更喜歡短元素標籤。
Github Repo: